From 7ce0fde009344d9b18f47d722f998e0d6a110271 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 24 Oct 2005 08:04:38 +0100 Subject: [PATCH] Attached patch avoids "Bad L1 flags 80" for VMX domains. Thanks Ian for the suggestions. Signed-off-by: Jun Nakajima --- xen/arch/x86/shadow.c | 27 +++++++++++++++++++++++++-- xen/arch/x86/shadow32.c | 27 +++++++++++++++++++++++++-- xen/include/asm-x86/shadow.h | 14 +++++++++++--- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index dfea7b4f43..fdd0c5aaf0 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -871,6 +871,7 @@ mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn, perfc_incrc(shadow_mark_mfn_out_of_sync_calls); + entry->v = v; entry->gpfn = gpfn; entry->gmfn = mfn; entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn); @@ -937,6 +938,7 @@ static void shadow_mark_va_out_of_sync( entry->writable_pl1e = l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * l1_table_offset(va)); ASSERT( !(entry->writable_pl1e & (sizeof(l1_pgentry_t)-1)) ); + entry->va = va; // Increment shadow's page count to represent the reference // inherent in entry->writable_pl1e @@ -1340,6 +1342,7 @@ static int resync_all(struct domain *d, u32 stype) guest_l1_pgentry_t *guest1 = guest; l1_pgentry_t *shadow1 = shadow; guest_l1_pgentry_t *snapshot1 = snapshot; + int unshadow_l1 = 0; ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) || shadow_mode_write_all(d)); @@ -1358,8 +1361,15 @@ static int resync_all(struct domain *d, u32 stype) if ( (i < min_snapshot) || (i > max_snapshot) || guest_l1e_has_changed(guest1[i], snapshot1[i], PAGE_FLAG_MASK) ) { - need_flush |= validate_pte_change(d, guest1[i], &shadow1[i]); - set_guest_back_ptr(d, shadow1[i], smfn, i); + int error; + + error = validate_pte_change(d, guest1[i], &shadow1[i]); + if ( error == -1 ) + unshadow_l1 = 1; + else { + need_flush |= error; + set_guest_back_ptr(d, shadow1[i], smfn, i); + } // can't update snapshots of linear page tables -- they // are used multiple times... // @@ -1371,6 +1381,19 @@ static int resync_all(struct domain *d, u32 stype) perfc_incrc(resync_l1); perfc_incr_histo(wpt_updates, changed, PT_UPDATES); perfc_incr_histo(l1_entries_checked, max_shadow - min_shadow + 1, PT_UPDATES); + if (unshadow_l1) { + pgentry_64_t l2e; + + __shadow_get_l2e(entry->v, entry->va, &l2e); + if (entry_get_flags(l2e) & _PAGE_PRESENT) { + entry_remove_flags(l2e, _PAGE_PRESENT); + __shadow_set_l2e(entry->v, entry->va, &l2e); + + if (entry->v == current) + need_flush = 1; + } + } + break; } #if defined (__i386__) diff --git a/xen/arch/x86/shadow32.c b/xen/arch/x86/shadow32.c index 18b5dc448f..5293e11843 100644 --- a/xen/arch/x86/shadow32.c +++ b/xen/arch/x86/shadow32.c @@ -1829,6 +1829,7 @@ shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn, perfc_incrc(shadow_mark_mfn_out_of_sync_calls); + entry->v = v; entry->gpfn = gpfn; entry->gmfn = mfn; entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn); @@ -1875,6 +1876,7 @@ void shadow_mark_va_out_of_sync( entry->writable_pl1e = l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * l1_table_offset(va)); ASSERT( !(entry->writable_pl1e & (sizeof(l1_pgentry_t)-1)) ); + entry->va = va; // Increment shadow's page count to represent the reference // inherent in entry->writable_pl1e @@ -2320,6 +2322,7 @@ static int resync_all(struct domain *d, u32 stype) l1_pgentry_t *guest1 = guest; l1_pgentry_t *shadow1 = shadow; l1_pgentry_t *snapshot1 = snapshot; + int unshadow_l1 = 0; ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) || shadow_mode_write_all(d)); @@ -2346,8 +2349,15 @@ static int resync_all(struct domain *d, u32 stype) if ( (i < min_snapshot) || (i > max_snapshot) || l1e_has_changed(guest1[i], snapshot1[i], PAGE_FLAG_MASK) ) { - need_flush |= validate_pte_change(d, guest1[i], &shadow1[i]); - set_guest_back_ptr(d, shadow1[i], smfn, i); + int error; + + error = validate_pte_change(d, guest1[i], &shadow1[i]); + if ( error == -1 ) + unshadow_l1 = 1; + else { + need_flush |= error; + set_guest_back_ptr(d, shadow1[i], smfn, i); + } // can't update snapshots of linear page tables -- they // are used multiple times... @@ -2359,6 +2369,19 @@ static int resync_all(struct domain *d, u32 stype) perfc_incrc(resync_l1); perfc_incr_histo(wpt_updates, changed, PT_UPDATES); perfc_incr_histo(l1_entries_checked, max_shadow - min_shadow + 1, PT_UPDATES); + if (unshadow_l1) { + l2_pgentry_t l2e; + + __shadow_get_l2e(entry->v, entry->va, &l2e); + if (l2e_get_flags(l2e) & _PAGE_PRESENT) { + l2e_remove_flags(l2e, _PAGE_PRESENT); + __shadow_set_l2e(entry->v, entry->va, l2e); + + if (entry->v == current) + need_flush = 1; + } + } + break; } case PGT_l2_shadow: diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 93bd92aaf7..0a8112c3d3 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -302,10 +302,12 @@ struct shadow_status { struct out_of_sync_entry { struct out_of_sync_entry *next; + struct vcpu *v; unsigned long gpfn; /* why is this here? */ unsigned long gmfn; unsigned long snapshot_mfn; unsigned long writable_pl1e; /* NB: this is a machine address */ + unsigned long va; }; #define out_of_sync_extra_size 127 @@ -384,6 +386,10 @@ shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d) nl1e = l1e; l1e_remove_flags(nl1e, _PAGE_GLOBAL); + + if ( unlikely(l1e_get_flags(l1e) & L1_DISALLOW_MASK) ) + return 0; + res = get_page_from_l1e(nl1e, d); if ( unlikely(!res) && IS_PRIV(d) && !shadow_mode_translate(d) && @@ -959,14 +965,16 @@ validate_pte_change( // perfc_incrc(validate_pte_changes3); - if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(new_spte, d) ) - new_spte = l1e_empty(); if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) { shadow_put_page_from_l1e(old_spte, d); need_flush = 1; } + if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && + !shadow_get_page_from_l1e(new_spte, d) ) { + new_spte = l1e_empty(); + need_flush = -1; /* need to unshadow the page */ + } } else { -- 2.30.2